import {
  ref,
  unref,
  ComputedRef,
  computed,
  onMounted,
  watch,
  reactive,
  Ref,
  watchEffect,
} from 'vue';
import { VxeGridPropTypes, VxeTablePropTypes, VxeGridInstance } from 'vxe-table';
import { useTimeoutFn } from '@vben/hooks';

import { get } from 'lodash-es';

import { FilterRule, FilterGroup, SortCondition, PageRequest } from '@/utils/common/types';
import { isFunction, isArray } from '@/utils/is';

import { FilterOperateEnum } from '@/enums/filterOperateEnum';
import { ListSortDirectionEnum } from '@/enums/listSortDirectionEnum';

import type { TableProps, FetchParams } from '../types/table';
import { handleFilterGroup } from '../types/table';
import { PAGE_SIZE } from '../const';

interface ActionType {
  getPaginationInfo: ComputedRef<VxeGridPropTypes.PagerConfig>;
  tableDataRef: Ref<VxeTablePropTypes.Data>;
  setPagination: (info: Partial<VxeGridPropTypes.PagerConfig>) => void;
  setLoading: (loading: boolean) => void;
  getSearchInfo: () => FilterGroup;
}

interface SearchState {
  sortInfo: Recordable;
  filterInfo: Record<string, string[]>;
}

/**
 * 使用数据源
 * @param propsRef 表格选项
 * @returns 数据源对象
 */
export function useDataSource(
  propsRef: ComputedRef<TableProps>,
  tableRef: ComputedRef<VxeGridInstance | undefined>,
  { getPaginationInfo, tableDataRef, setPagination, setLoading, getSearchInfo }: ActionType,
  emit: EmitType,
) {
  const searchState = reactive<SearchState>({
    sortInfo: {},
    filterInfo: {},
  });
  const dataRef = ref<Recordable[]>([]);
  const searchInfoRef = ref<Recordable>({});

  watchEffect(() => {
    tableDataRef.value = unref(dataRef);
  });

  watch(
    () => unref(propsRef).data,
    () => {
      const { data, api } = unref(propsRef);
      !api && data && (dataRef.value = data);
    },
    {
      immediate: true,
    },
  );

  async function handleChange(e?: Recordable) {
    const table = unref(tableRef);
    const pagination: VxeGridPropTypes.PagerConfig = {
      ...table?.pagerConfig,
      currentPage: e?.currentPage || table?.pagerConfig?.currentPage,
      pageSize: e?.pageSize || table?.pagerConfig?.pageSize,
    };
    const sorter = table?.getSortColumns() || [];

    const { clearSelectOnPageChange } = unref(propsRef);
    if (clearSelectOnPageChange) {
      await table?.clearSelected();
    }
    setPagination(pagination);

    const params: Recordable = {};
    searchState.sortInfo = sorter;
    params.sortInfo = sorter;

    // searchState.filterInfo = filter;
    // params.filterInfo = filter;

    fetch(params);
  }

  const getDataRef = computed(() => {
    const data = unref(dataRef);
    if (!data || data.length === 0) {
      return unref(dataRef);
    }
    return unref(dataRef);
  });

  /** 重新定义取数逻辑，以配合后台。 */
  async function fetch(opt?: FetchParams) {
    //TODO:定义请求体
    let pageRequest: PageRequest = new PageRequest();

    const { api, searchInfo, beforeFetch, afterFetch, searchForm, columns } = unref(propsRef);
    if (!api || !isFunction(api)) return;
    try {
      setLoading(true);
      // const { pageField, sizeField, listField, totalField } = Object.assign(
      //   {},
      //   FETCH_SETTING,
      //   fetchSetting
      // );
      // let pageParams: Recordable = {};
      const listField = 'Rows';
      const totalField = 'Total';

      const { currentPage = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo);

      //TODO:设置请求体分页条件信息（页索引、页大小）
      pageRequest.PageCondition.PageIndex = (opt && opt.page) || currentPage;
      pageRequest.PageCondition.PageSize = pageSize;

      //TODO:设置请求体分页条件信息（排序条件组）
      const { sortInfo, filterInfo } = searchState;
      const sortConditions = handleSortConditions(sortInfo || opt?.sortInfo);
      pageRequest.PageCondition.SortConditions = [
        ...pageRequest.PageCondition.SortConditions,
        ...sortConditions,
      ];
      // console.log('排序条件组', pageRequest.PageCondition.SortConditions);

      //TODO:设置请求体查询条件组
      if (filterInfo) {
        const filterGroup = handlefilterGroup(filterInfo);
        // console.log('fetch-filterInfo', { filterInfo, filterGroup });

        if (filterGroup?.Groups?.length > 0 || filterGroup?.Rules?.length > 0) {
          const g = handleFilterGroup(filterGroup, columns);
          if (g.Operate && !pageRequest.FilterGroup.Groups.find((m) => m === g)) {
            pageRequest.FilterGroup.Groups.push(g);
          }
        }
      }
      if (opt?.filterInfo) {
        const filterGroup = handlefilterGroup(opt?.filterInfo);
        // console.log('fetch-opt?.filterInfo', { filterInfo: opt?.filterInfo, filterGroup });

        if (filterGroup?.Groups?.length > 0 || filterGroup?.Rules?.length > 0) {
          const g = handleFilterGroup(filterGroup, columns);
          if (g.Operate && !pageRequest.FilterGroup.Groups.find((m) => m === g)) {
            pageRequest.FilterGroup.Groups.push(g);
          }
        }
      }
      if (searchInfo) {
        //console.log('fetch-searchInfo', searchInfo);
        if (searchInfo?.Groups?.length > 0 || searchInfo?.Rules?.length > 0) {
          const g = handleFilterGroup(searchInfo, columns);
          if (g.Operate && !pageRequest.FilterGroup.Groups.find((m) => m === g)) {
            pageRequest.FilterGroup.Groups.push(g);
          }
        }
      }
      if (opt?.searchInfo) {
        //console.log('fetch-opt?.searchInfo', opt?.searchInfo);
        if (opt?.searchInfo?.Groups?.length > 0 || opt?.searchInfo?.Rules?.length > 0) {
          const g = handleFilterGroup(opt?.searchInfo, columns);
          if (g.Operate && !pageRequest.FilterGroup.Groups.find((m) => m === g)) {
            pageRequest.FilterGroup.Groups.push(g);
          }
        }
      } else if (searchForm) {
        const group = getSearchInfo() as FilterGroup;
        if (group?.Groups?.length > 0 || group?.Rules?.length > 0) {
          const g = handleFilterGroup(group, columns);
          if (g.Operate && !pageRequest.FilterGroup.Groups.find((m) => m === g)) {
            pageRequest.FilterGroup.Groups.push(g);
          }
        }
      }

      // let params: Recordable = merge(
      //   pageParams,
      //   useSearchForm ? getFieldsValue() : {},
      //   searchInfo,
      //   opt?.searchInfo ?? {},
      //   defSort,
      //   sortInfo,
      //   filterInfo,
      //   opt?.sortInfo ?? {},
      //   opt?.filterInfo ?? {},
      // );
      // if (beforeFetch && isFunction(beforeFetch)) {
      //   params = (await beforeFetch(params)) || params;
      // }
      if (beforeFetch && isFunction(beforeFetch)) {
        pageRequest = (await beforeFetch(pageRequest)) || pageRequest;
      }
      // console.log('fetch', pageRequest);
      searchInfoRef.value = pageRequest;
      const res = await api(pageRequest);
      dataRef.value = res;

      const isArrayResult = Array.isArray(res);

      let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
      const resultTotal: bigint = isArrayResult ? BigInt(res.length) : BigInt(get(res, totalField));

      // 假如数据变少，导致总页数变少并小于当前选中页码，通过getPaginationRef获取到的页码是不正确的，需获取正确的页码再次执行
      if (resultTotal > 0) {
        const currentTotalPage = Math.ceil(Number(resultTotal) / pageSize);
        if (currentPage > currentTotalPage) {
          setPagination({
            currentPage: currentTotalPage,
          });
          return await fetch(opt);
        }
      }

      if (afterFetch && isFunction(afterFetch)) {
        resultItems = (await afterFetch(resultItems)) || resultItems;
      }
      dataRef.value = resultItems;
      setPagination({
        total: Number(resultTotal) || 0,
      });
      if (opt && opt.page) {
        setPagination({
          currentPage: opt.page || 1,
        });
      }
      emit('fetch-success', {
        items: unref(resultItems),
        total: resultTotal,
      });
      return resultItems;
    } catch (error) {
      emit('fetch-error', error);
      dataRef.value = [];
      setPagination({
        total: 0,
      });
    } finally {
      setLoading(false);
    }
  }

  /** 设置表格数据 */
  function setData<T = Recordable>(values: T[]) {
    dataRef.value = values as any[];
  }

  /** 获取表格数据 */
  function getData<T = Recordable>() {
    return dataRef.value as T[];
  }

  /** 重载表格数据 */
  async function reload(opt?: FetchParams) {
    return await fetch(opt);
  }

  function getSearchInfoFn<T = Recordable>() {
    return searchInfoRef.value as T;
  }

  onMounted(() => {
    useTimeoutFn(() => {
      unref(propsRef).immediate && fetch();
    }, 16);
  });

  /** 设置排序条件集合 */
  function handleSortConditions(sortInfo: Recordable): SortCondition[] {
    const sortConditions: SortCondition[] = [];
    if (!sortInfo) {
      return sortConditions;
    }
    if (isArray(sortInfo)) {
      sortInfo.forEach((item) => {
        if (item?.field && item?.order) {
          sortConditions.push({
            // 排序字段（The sort field passed to the backend you）
            SortField: item.field,
            // 排序方式 asc/desc（Sorting method passed to the background asc/desc）
            ListSortDirection:
              (item.order as string)?.toLowerCase() === 'desc'
                ? ListSortDirectionEnum.Descending
                : ListSortDirectionEnum.Ascending,
          });
        }
      });
    } else {
      const { field, order } = sortInfo;
      if (field && order) {
        sortConditions.push({
          // 排序字段（The sort field passed to the backend you）
          SortField: field,
          // 排序方式 asc/desc（Sorting method passed to the background asc/desc）
          ListSortDirection:
            (order as string)?.toLowerCase() === 'desc'
              ? ListSortDirectionEnum.Descending
              : ListSortDirectionEnum.Ascending,
        });
      }
    }
    // console.log('handleSortConditions', sortConditions);
    return sortConditions;
  }
  /** 设置查询条件组 */
  function handlefilterGroup(filterInfo: Partial<Recordable<string[]>>) {
    const filterGroup: FilterGroup = new FilterGroup();
    filterGroup.Operate = FilterOperateEnum.And;
    for (const filter in filterInfo) {
      const filterVals = filterInfo[filter];
      if (filterVals) {
        if (Array.isArray(filterVals) && filterVals.length > 0) {
          const subGroup: FilterGroup = new FilterGroup();
          subGroup.Operate = FilterOperateEnum.Or;
          for (const filterVal of filterVals) {
            const filterRule: FilterRule = new FilterRule(
              filter,
              filterVal,
              FilterOperateEnum.Equal,
            );
            subGroup.Rules = [...subGroup.Rules, ...[filterRule]];
          }
          if (subGroup.Rules.length > 0) {
            filterGroup.Groups = [...filterGroup.Groups, ...[subGroup]];
          }
        } else {
          const filterRule2: FilterRule = new FilterRule(
            filter,
            filterVals,
            FilterOperateEnum.Equal,
          );
          filterGroup.Rules = [...filterGroup.Rules, ...[filterRule2]];
        }
      }
    }
    // console.log('filterGroup', filterGroup);
    return filterGroup;
  }

  return {
    getDataRef,
    getData,
    searchInfoRef,
    getSearchInfo: getSearchInfoFn,
    setData,
    fetch,
    reload,
    handleChange,
  };
}
